/**
 *YCL 模板引擎
 */
(function () {
    var argsRe = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
        nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
        ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
        execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
        codeRe = /\{\[((?:\\\]|.|\n)*?)\]\}/g,
        re=/\{([\w-\.\#]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\/]\s?[\d\.\+\-\*\/\(\)]+)?\}/g,
        tpls = [],
        compileARe = /\\/g,
        compileBRe = /(\r\n|\n)/g,
        compileCRe = /'/g,
        master = null;
    /**
     * 构造器
     * @param html 模板引擎
     * @param node 节点定义
     * @json  json json数据
     */
    this.YCL.template = function (html,node,json) {
        html = ['<tpl>', html, '</tpl>'].join('');
        var m, exp, fn, exec, matchName, matchIf, matchExec, name, id = 0, i;
        var NODE = 'node',
            JSON = 'json',
            PARENT = 'parent',
            XINDEX = 'xindex',
            XCOUNT = 'xcount',
            RETURN = 'return ',
            WITHNODE = 'with(node){ ';
        while ((m = html.match(argsRe))) {
            exp = null;
            fn = null;
            exec = null;
            matchName = m[0].match(nameRe);
            matchIf = m[0].match(ifRe);
            matchExec = m[0].match(execRe);
            exp = matchIf ? matchIf[1] : null;
            if (exp) {
                //todo if表达式
                fn = funcFactory(NODE, JSON, PARENT, XINDEX, XCOUNT, 'try{' + RETURN + htmlDecode(exp) + ';}catch(e){return;}');
            }
            exp = matchExec ? matchExec[1] : null;
            if (exp) {
                //todo exec表达式 执行一段代码
                exec = funcFactory(NODE, JSON, XINDEX, XCOUNT, WITHNODE + htmlDecode(exp) + ';}');
            }
            name = matchName ? matchName[1] : null;
            if (name) {
                //todo for循环,指定要循环的target,也就是for='name'中的name指向哪个数据块
                name = funcFactory(NODE, JSON, PARENT, 'try{with(' + JSON + '){' + RETURN + name + ';}}catch(e){return;}');
            }
            tpls.push({id:id, target:name, exec:exec, test:fn, body:m[1] || ''});
            html = html.replace(m[0], '{xtpl' + id + '}');
            id = id + 1;
        }
        for (i = tpls.length - 1; i >= 0; --i) {
            compileTpl(tpls[i]);
        }
        //todo 暂时去掉,用到的时候再说.
          master = tpls[tpls.length - 1];
//        me.tpls = tpls;
        return applyTemplate(node,json);
    };
    var compileTpl = function (tpl) {
        var body, bodyReturn, evaluatedFn, useFormat = false;
        var fn = function (me,name, format, args, math) {
            var v;
            if (name.substr(0, 4) == 'xtpl') {
                return "',applySubTemplate(" + name.substr(4) + ",node,json,parent,xindex,xcount),'";
            }
            if (name == '.') {
                //可能无用
                v = '["string", "number", "boolean"].indexOf(Type.(node)) > -1 || me.isDate(node) ? node : ""';
            } else if (name == '#') {
                //如果是{#}号，则自动填充索引号
                v = 'xindex';
            } else if (name.substr(0, 7) == "parent.") {
                //如果是parent. 则从el的parentNode取值
                v = "Type.isElement(node)?$(node.parentNode).get('" + name.substr(7) + "'):$(parent).get('" + name.substr(7) + "')";
            } else if (name.indexOf('.') != -1) {
                //如果是{.aaa} 则从json里直接取值
                v = "json." + name;
            } else {
                //默认从node里取值,但是node里如果没有,则从json里取，都没有，那么值为空
                v = "((Type.isElement(node)?node.get('" + name + "'):node['" + name + "'])||json['" + name + "'])";
            }
            //todo 这句话可能也没用
            if (math) v = '(' + v + math + ')';
            //todo 这里的代码可能也没用
            if (format && useFormat) {
                args = args ? ',' + args : "";
                if (format.substr(0, 5) != "this.") {
                    format = "fm." + format + '(';
                }
                else {
                    format = 'this.' + format.substr(5) + '(';
                }
            } else {
                args = '';
                format = "(" + v + " === undefined ? '' : ";
            }
            return "'," + format + v + args + "),'";
        };
        var codeFn = function (me,code) {
            return "',(" + code.replace(compileARe, "'") + "),'";
        };
        bodyReturn = tpl.body.replace(compileBRe, '\\n').replace(compileCRe, "\\'").replace(re, fn).replace(codeRe, codeFn);
        body = "evaluatedFn = function(node,json,parent,xindex,xcount){return ['" + bodyReturn + "'].join('');};";
        eval(body);
        tpl.compiled = function (node, json, parent, xindex, xcount) {
            var vs, length, buffer, i,j;
            if (tpl.test && !tpl.test.call(node, json, parent, xindex, xcount)) {
                return '';
            }
            //todo 取到for循环的name指向的数据块(数据块可能是element数组,也可能是JOSN数据数组)
            vs = tpl.target ? tpl.target.call(node, json, parent) : (node || {});
            if (!vs) {
                return '';
            }
            parent = tpl.target ? node : parent;
            if (tpl.target && Type.isArray(vs)) {
                buffer = [];
                length = vs.length;
                if (tpl.exec) {
                    for (i = 0; i < length; i++) {
                        buffer[buffer.length] = evaluatedFn.call(vs[i],json,parent, i + 1, length);
                        tpl.exec.call(vs[i], parent,i + 1,length);
                    }
                } else {
                    for (j = 0; j< length; j++) {
                        buffer[buffer.length] = evaluatedFn.call(vs[j], json, parent, j + 1, length);
                    }
                }
                return buffer.join('');
            }
            if (tpl.exec) {
                tpl.exec.call(vs, parent, xindex, xcount);
            }
            return evaluatedFn.call(this,vs, json, parent, xindex, xcount);
        };
    };
    var applyTemplate = function (node, json) {
        return master.compiled.call(this, node, json, {}, 1, 1);
    };
    var applySubTemplate = function (id, node, json, parent, xindex, xcount) {
        var t = tpls[id];
        return t.compiled.call(this, node, json, parent, xindex, xcount);
    };
    var funcFactory = function () {
        return Function.prototype.constructor.apply(Function.prototype, Array.prototype.slice.call(arguments));
    };
    var htmlDecode = function (exp) {
        var entities = {
            '&amp;':'&',
            '&gt;':'>',
            '&lt;':'<',
            '&quot;':'"'
        }, keys = [], p, regex;
        for (p in entities) {
            keys.push(p);
        }
        regex = new RegExp('(' + keys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
        var returns = function () {
            return (!exp) ? exp : String(exp).replace(regex, function (match, capture) {
                if (capture in entities) {
                    return entities[capture];
                } else {
                    return String.fromCharCode(parseInt(capture.substr(2), 10));
                }
            });
        };
        return returns();
    }
})();
